﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Kinect;
using Microsoft.Speech.AudioFormat;
using Microsoft.Speech.Recognition;
using System.IO;

namespace physio.assist
{
    /// <summary>
    /// Interaction logic for PhysioAssist.xaml
    /// </summary>
    public partial class PhysioAssist : Window
    {


        private KinectSensor sensor;
        private WriteableBitmap colorBitmap;
        private SpeechRecognitionEngine speechEngine;
        private byte[] colorPixels;
        private List<PhysioAssistWS.MovimentoLog> lstMovimentoLog = new List<PhysioAssistWS.MovimentoLog>();
        Skeleton[] sklts = new Skeleton[6];




        //KINECT
        private void winPhysio_Loaded(object sender, RoutedEventArgs e)
        {
            //Obtem o sensor ativo
            foreach (var potentialSensor in KinectSensor.KinectSensors)
            {
                if (potentialSensor.Status == KinectStatus.Connected)
                {
                    sensor = potentialSensor;
                    break;
                }
            }


            if (null != sensor)
            {

                //Habilita imagem e esqueletos
                sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                sensor.SkeletonStream.Enable();

                //Preparação da imagem do Kinect
                colorPixels = new byte[sensor.ColorStream.FramePixelDataLength];
                colorBitmap = new WriteableBitmap(sensor.ColorStream.FrameWidth, sensor.ColorStream.FrameHeight, 96.0, 96.0, PixelFormats.Bgr32, null);
                imgKinect.Source = colorBitmap;

                //Eventos de Frame Ready
                sensor.ColorFrameReady += sensor_ColorFrameReady;
                sensor.SkeletonFrameReady += sensor_SkeletonFrameReady;

                try
                {
                    sensor.Start();
                }
                catch (IOException)
                {
                    sensor = null;
                }
            }








            //RECONHECIMENTO DE VOZ
            RecognizerInfo ri = GetKinectRecognizer();

            if (null != ri)
            {

                this.speechEngine = new SpeechRecognitionEngine(ri.Id);

                // Create a grammar from grammar definition XML file.
                using (var memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(Properties.Resources.PhysioAssistGrammar)))
                {
                    var g = new Grammar(memoryStream);
                    speechEngine.LoadGrammar(g);
                }

                speechEngine.SpeechRecognized += SpeechRecognized;

                speechEngine.SetInputToAudioStream(sensor.AudioSource.Start(), new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
                speechEngine.RecognizeAsync(RecognizeMode.Multiple);
            }
            else
            {
                lblNome.Content = "Erro";
            }










        }
        private void winPhysio_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //Ao fechar a janela, salvar os dados armazenados no banco
            SalvaLog();


            //E desocupar o Kinect
            if (null != this.sensor)
            {
                this.sensor.Stop();
            }
        }
        void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {




            //Reseta cor do quadro do vídeo
            pnlVideo.Background = Brushes.SteelBlue;
            lblKinect.Visibility = System.Windows.Visibility.Hidden;



            SkeletonFrame sf = e.OpenSkeletonFrame();

            if (sf != null)
            {

                //Cria array de esqueletos e recebe o skeletonframe
                sf.CopySkeletonDataTo(sklts);


                //Cria esqueleto
                Skeleton sklt = new Skeleton();


                //Pega primeiro esqueleto traqueado
                foreach (Skeleton sk in sklts)
                {
                    if (sk.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        sklt = sk;
                        break;
                    }
                }





                //Só entra aqui se existir um esqueleto traqueado
                if (sklt.TrackingState == SkeletonTrackingState.Tracked)
                {




                    //Pinta a janela do vídeo quando tem esqueleto reconhecido
                    pnlVideo.Background = Brushes.DarkOrchid;
                    lblKinect.Visibility = System.Windows.Visibility.Visible;



                    //A cada trinta quadros, insere movimento na log de movimentos
                    if (sf.FrameNumber % 30 == 0)
                    {
                        //Loga todas as juntas no banco
                        DateTime agora = DateTime.Now;
                        foreach (Joint junta in sklt.Joints)
                        {
                            PhysioAssistWS.MovimentoLog log = new PhysioAssistWS.MovimentoLog();

                            log.Data = agora;
                            log.Junta = junta.JointType.ToString();
                            log.Paciente = 1;//hardcode
                            log.Profissional = 1;//hardcode
                            log.X = junta.Position.X;
                            log.Y = junta.Position.Y;
                            log.Z = junta.Position.Z;

                            lstMovimentoLog.Add(log);

                        }
                    }



                    //Quando a lista de juntas estiver muito grande, grava no banco e a limpa
                    if (lstMovimentoLog.Count > 100)
                    {
                        System.Threading.Thread t = new System.Threading.Thread(SalvaLog);
                        t.Start();
                    }







                }






            }

        }
        void sensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    colorFrame.CopyPixelDataTo(this.colorPixels);

                    this.colorBitmap.WritePixels(
                        new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
                        this.colorPixels,
                        this.colorBitmap.PixelWidth * sizeof(int),
                        0);
                }
            }
        }
        private void SalvaLog()
        {
            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();
            ws.InsereMovimentoLog(lstMovimentoLog.ToArray());

            lstMovimentoLog.Clear();
        }





        //INICIALIZA JANELA
        public PhysioAssist()
        {
            InitializeComponent();



            //Ajusta posição e tamanho das janelas
            double width = System.Windows.SystemParameters.PrimaryScreenWidth;
            double height = System.Windows.SystemParameters.PrimaryScreenHeight;

            winPhysio.Width = width;
            winPhysio.Height = height;


            //Ajusta width dos paineis
            pnlEsquerdo.Width = (width / 10) * 3;
            pnlCentral.Width = (width / 10) * 5;
            pnlDireita.Width = (width / 10) * 1.8;


            //Ajusta height dos paineis
            pnlEsquerdo.Height = height - 20;
            pnlCentral.Height = height - 20;
            pnlDireita.Height = height - 20;


            //Ajusta Left dos paineis
            pnlEsquerdo.Margin = new Thickness(10, 10, 0, 0);
            pnlCentral.Margin = new Thickness(pnlEsquerdo.Width + 12, 10, 0, 0);
            pnlDireita.Margin = new Thickness(pnlEsquerdo.Width + pnlCentral.Width + 25, 10, 0, 0);






            //Ajusta tamanho e posicao dos paineis do paciente
            pnlGrafico01.Height = (pnlEsquerdo.Height / 4) - 10;
            pnlGrafico02.Height = (pnlEsquerdo.Height / 4) - 10;
            pnlGrafico03.Height = (pnlEsquerdo.Height / 4) - 10;
            pnlPaciente.Height = (pnlEsquerdo.Height / 4);

            pnlGrafico02.Margin = new Thickness(0, 10, 0, 0);
            pnlGrafico03.Margin = new Thickness(0, 10, 0, 0);
            pnlPaciente.Margin = new Thickness(0, 10, 0, 0);

            pnlGrafico01.Width = pnlEsquerdo.Width - 10;
            pnlGrafico02.Width = pnlEsquerdo.Width - 10;
            pnlGrafico03.Width = pnlEsquerdo.Width - 10;
            pnlPaciente.Width = pnlEsquerdo.Width - 10;






            //Ajusta tamanho e posicao dos paineis de vídeo, noticia e anuncio
            pnlVideo.Width = pnlCentral.Width;
            pnlNoticiasAnuncios.Width = pnlCentral.Width;
            pnlNoticias.Width = pnlNoticiasAnuncios.Width * 0.5 - 5;
            pnlAnuncios.Width = pnlNoticiasAnuncios.Width * 0.5 - 5;

            pnlNoticiasAnuncios.Margin = new Thickness(0, 10, 0, 0);

            pnlVideo.Height = pnlCentral.Height * 0.75 - 10;
            pnlNoticiasAnuncios.Height = pnlCentral.Height * 0.25;
            pnlNoticias.Height = pnlNoticiasAnuncios.Height;
            pnlAnuncios.Height = pnlNoticiasAnuncios.Height;


            pnlNoticias.Margin = new Thickness(10, 0, 0, 0);






            //Ajusta tamanho e posicao dos paineis de agenda e aniversarios
            pnlAgenda.Width = pnlDireita.Width;
            pnlAniversarios.Width = pnlDireita.Width;

            pnlAgenda.Height = pnlDireita.Height * 0.75 - 10;
            pnlAniversarios.Height = pnlDireita.Height * 0.25;

            pnlAniversarios.Margin = new Thickness(0, 10, 0, 0);



            //Inicializa dados
            InicializaDados();



        }








        //INICIALIZA DADOS
        private void InicializaDados()
        {


            //Lista Compromissos
            int profissional = 1;//hardcode
            int dia = DateTime.Now.Day;
            int mes = DateTime.Now.Month;
            int ano = DateTime.Now.Year;

            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();
            foreach (PhysioAssistWS.Agenda agenda in ws.ListaAgenda(profissional, dia, mes, ano))
            {
                if (agenda.Compromisso == "Almoço")//Quando for almoço, adiciona dois espaços
                { ListaCompromissos("", ""); ListaCompromissos(agenda.Hora, agenda.Compromisso); ListaCompromissos("", ""); }
                else ListaCompromissos(agenda.Hora, agenda.Compromisso);
            }




            //Lista aniversários do dia
            ListaAniversarios(DateTime.Now.Day, DateTime.Now.Month);


            //Lista notícias mais recentes
            ListaNoticias();


            //Lista anúncios
            ListaAnuncios();



            //Carrega informações do Paciente
            CarregaPaciente(1);//hardcode



            //Carrega labels de desempenho do paciente
            CarregaInformacoeJunta(1, "Pescoço", 7, lblPescoco7, "angulo", "media");//hardcode
            CarregaInformacoeJunta(1, "Tronco", 7, lblTronco7, "angulo", "media");//hardcode
            CarregaInformacoeJunta(1, "Braços", 7, lblBracos7, "angulo", "media");//hardcode


            CarregaInformacoeJunta(1, "Pescoço", 30, lblPescoco30, "angulo", "media");//hardcode
            CarregaInformacoeJunta(1, "Tronco", 30, lblTronco30, "angulo", "media");//hardcode
            CarregaInformacoeJunta(1, "Braços", 30, lblBracos30, "angulo", "media");//hardcode


            CarregaInformacoeJunta(1, "Pescoço", 365, lblPescocoGeral, "tempo", "media");//hardcode
            CarregaInformacoeJunta(1, "Tronco", 365, lblTroncoGeral, "tempo", "media");//hardcode
            CarregaInformacoeJunta(1, "Braços", 365, lblBracosGeral, "tempo", "media");//hardcode




        }










        //AGENDA
        private void ListaCompromissos(string hora, string compromisso)
        {

            //Cria stack horizontal
            StackPanel pnl = new StackPanel();
            pnl.Orientation = Orientation.Horizontal;

            //Cria label hora
            Label lblHora = new Label();
            BrushConverter bc = new BrushConverter();
            lblHora.FontSize = 20;
            lblHora.Foreground = Brushes.White;
            lblHora.Content = hora;

            //Cria label compromisso
            Label lblCompromisso = new Label();
            lblCompromisso.FontSize = 20;
            lblCompromisso.Content = compromisso;

            //Insere labels no panel
            pnl.Children.Add(lblHora);
            pnl.Children.Add(lblCompromisso);

            //Insere panel no panel principal
            pnlAgenda.Children.Add(pnl);


        }


        //ANIVERSARIOS
        private void ListaAniversarios(int dia, int mes)
        {

            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();

            foreach (PhysioAssistWS.Aniversario aniversario in ws.ListaAniversario(dia, mes))
            {

                InsereAniversario(dia, mes, aniversario.Nome);

            }

        }
        private void InsereAniversario(int dia, int mes, string nome)
        {

            //Cria o panel
            StackPanel pnl = new StackPanel();
            pnl.Orientation = Orientation.Horizontal;
            pnl.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;

            //Cria imagem do bolo
            Image img = new Image();
            img.Source = new BitmapImage(new Uri(@"pack://application:,,,/physio.assist;component/Images/bolo.png"));

            //Cria label da data
            Label lblData = new Label();
            lblData.Content = dia + "/" + mes;
            lblData.FontSize = 20;
            lblData.Foreground = Brushes.White;

            //Cria label do nome
            Label lblNome = new Label();
            // lblNome.FontWeight = FontWeights.Bold;
            lblNome.FontSize = 20;
            lblNome.Content = nome;

            //Insere componente no panel
            //pnl.Children.Add(img);
            pnl.Children.Add(lblData);
            pnl.Children.Add(lblNome);

            //Insere panel no panel de aniversarios
            pnlAniversarios.Children.Add(pnl);

        }


        //NOTICIAS
        private void ListaNoticias()
        {

            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();

            foreach (PhysioAssistWS.Noticia noticia in ws.ListaNoticia())
            {

                InsereNoticia(noticia);

            }

        }
        private void InsereNoticia(PhysioAssistWS.Noticia noticia)
        {

            //Cria o panel
            StackPanel pnl = new StackPanel();
            pnl.Orientation = Orientation.Horizontal;
            pnl.VerticalAlignment = System.Windows.VerticalAlignment.Center;

            //Cria label da data
            Label lblData = new Label();
            lblData.Content = noticia.Data.ToShortDateString();
            lblData.FontSize = 15;
            lblData.Foreground = Brushes.Silver;

            //Cria label da fonte
            Label lblFonte = new Label();
            lblFonte.Content = noticia.Fonte;
            lblFonte.FontSize = 15;
            lblFonte.Foreground = Brushes.White;

            //Cria label do titulo
            Label lblTitulo = new Label();
            lblTitulo.Content = noticia.Titulo;
            lblTitulo.FontSize = 15;

            //Insere componente no panel
            pnl.Children.Add(lblData);
            pnl.Children.Add(lblFonte);
            pnl.Children.Add(lblTitulo);

            //Insere panel no panel de aniversarios
            pnlNoticias.Children.Add(pnl);

        }


        //ANUNCIOS
        private void ListaAnuncios()
        {
            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();

            foreach (PhysioAssistWS.Anuncio anuncio in ws.ListaAnuncio())
            {

                InsereAnuncio(anuncio, "Rodrigo");

            }
        }
        private void InsereAnuncio(PhysioAssistWS.Anuncio anuncio, string pessoa)
        {

            //Cria o panel
            StackPanel pnl = new StackPanel();
            pnl.Orientation = Orientation.Horizontal;
            pnl.VerticalAlignment = System.Windows.VerticalAlignment.Center;

            //Cria label da data
            Label lblData = new Label();
            lblData.Content = anuncio.Data.ToShortDateString();
            lblData.FontSize = 15;
            lblData.Foreground = Brushes.Silver;

            //Cria label da pessoa que enviou o anuncio
            Label lblProfissional = new Label();
            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();
            PhysioAssistWS.Profissional profissional = ws.GetProfissional(anuncio.Profissional);
            lblProfissional.Content = " por " + profissional.Nome;
            lblProfissional.FontSize = 15;
            lblProfissional.Foreground = Brushes.White;

            //Cria label da mensagem
            Label lblMensagem = new Label();
            lblMensagem.Content = anuncio.Mensagem;
            lblMensagem.FontSize = 15;

            //Insere componente no panel
            pnl.Children.Add(lblData);
            pnl.Children.Add(lblProfissional);
            pnl.Children.Add(lblMensagem);

            //Insere panel no panel de aniversarios
            pnlAnuncios.Children.Add(pnl);

        }


        //PACIENTE
        private void CarregaPaciente(int id)
        {

            //Pega as informações do paciente
            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();
            PhysioAssistWS.Paciente paciente = ws.GetPaciente(id);

            //Carrega label de nome
            lblNome.Content = paciente.Nome;

            //Carrega label de idade
            //TimeSpan span = DateTime.Now.Subtract(paciente.Nascimento);
            //int years = (int)(span.Days / 365.25);
            //lblIdade.Content = years;

            //Aumenta tamanho da imagem
            imgPaciente.Height = pnlPaciente.Height * 0.83;
            imgPaciente.Stretch = Stretch.Fill;


        }


        //DESEMPENHO
        private void CarregaInformacoeJunta(int paciente, string junta, int ultimosXdias, Label lbl, string anguloOUtempo, string MaxMinMedia)
        {

            //Obtem valor comparativo do histórico geral do paciente com seu desempenho na ultima semana
            PhysioAssistWS.PhysioAssistSoapClient ws = new PhysioAssistWS.PhysioAssistSoapClient();
            double valor = ws.Compara(DateTime.Now.AddYears(-1000), DateTime.Now.AddDays(-ultimosXdias - 1), DateTime.Now.AddDays(-ultimosXdias), DateTime.Now, anguloOUtempo, MaxMinMedia, junta, paciente);
            lbl.Foreground = Brushes.Black;



            TextBlock txt = new TextBlock();

            //Compara se o desempenho evoluiu ou regrediu
            if (valor > 0)
            {
                txt = new TextBlock();
                txt.Inlines.Add("O ");
                txt.Inlines.Add(FormataPalavra(anguloOUtempo, Brushes.MintCream));
                txt.Inlines.Add(FormataPalavra(" evoluiu", Brushes.DodgerBlue));
                txt.Inlines.Add(" cerca de ");
                txt.Inlines.Add(FormataPalavra(Math.Round(valor, 0).ToString() + "%", Brushes.MintCream));
                txt.Inlines.Add(" nos últimos ");
                txt.Inlines.Add(FormataPalavra(ultimosXdias.ToString() + " dias", Brushes.MintCream));

                lbl.Content = txt;
            }
            if (valor < 0)
            {
                txt = new TextBlock();
                txt.Inlines.Add("O ");
                txt.Inlines.Add(FormataPalavra(anguloOUtempo, Brushes.MintCream));
                txt.Inlines.Add(FormataPalavra(" regrediu", Brushes.Firebrick));
                txt.Inlines.Add(" cerca de ");
                txt.Inlines.Add(FormataPalavra(Math.Round(valor, 0).ToString() + "%", Brushes.MintCream));
                txt.Inlines.Add(" nos últimos ");
                txt.Inlines.Add(FormataPalavra(ultimosXdias.ToString() + " dias", Brushes.MintCream));
                txt.Inlines.Add(" dias");

                lbl.Content = txt;
            }
            if (valor == 0)
            {
                txt = new TextBlock();
                txt.Inlines.Add("O ");
                txt.Inlines.Add(FormataPalavra(anguloOUtempo, Brushes.MintCream));
                txt.Inlines.Add(" está estável nos últimos ");
                txt.Inlines.Add(FormataPalavra(ultimosXdias.ToString() + " dias", Brushes.MintCream));

                lbl.Content = txt;
            }

        }
        private Run FormataPalavra(string palavra, Brush cor)
        {
            Run run = new Run();
            //run.FontWeight = FontWeights.Bold;
            run.Foreground = cor;
            run.Text = palavra;

            return run;
        }








        //RECONHECIMENTO DE VOZ
        private static RecognizerInfo GetKinectRecognizer()
        {
            foreach (RecognizerInfo recognizer in SpeechRecognitionEngine.InstalledRecognizers())
            {
                string value;
                recognizer.AdditionalInfo.TryGetValue("Kinect", out value);
                if ("True".Equals(value, StringComparison.OrdinalIgnoreCase) && "en-US".Equals(recognizer.Culture.Name, StringComparison.OrdinalIgnoreCase))
                {
                    return recognizer;
                }
            }

            return null;
        }
        private void SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            // Speech utterance confidence below which we treat speech as if it hadn't been heard
            const double ConfidenceThreshold = 0.3;

            if (e.Result.Confidence >= ConfidenceThreshold)
            {
                switch (e.Result.Semantics.Value.ToString())
                {
                    case "BRASSOS":
                        Bracos winBracos = new Bracos();
                        winBracos.Show();
                        break;

                    case "TRONKO":
                        Tronco winTronco = new Tronco();
                        winTronco.Show();
                        break;

                    case "PESKOSSO":
                        Pescoco winPescoco = new Pescoco();
                        winPescoco.Show();
                        break;





                    case "NOTISSIA":
                        Noticias winNoticias = new Noticias();
                        winNoticias.Show();
                        break;

                    case "ANOONSSYO":
                        Anuncios winAnuncios = new Anuncios();
                        winAnuncios.Show();
                        break;





                    case "AGENDA":
                        Agenda winAgenda = new Agenda();
                        winAgenda.Show();
                        break;





                    case "ANIVERSSARIO":
                        Aniversarios winAniversarios = new Aniversarios();
                        winAniversarios.Show();
                        break;
                }
            }
        }





        //Abrir com cliques
        private void imgPaciente_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Pacientes win = new Pacientes();
            win.Show();
        }
        private void pnlGrafico01_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Pescoco win = new Pescoco();
            win.Show();
        }
        private void pnlGrafico02_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Tronco win = new Tronco();
            win.Show();
        }
        private void pnlGrafico03_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Bracos win = new Bracos();
            win.Show();
        }
        private void pnlAnuncios_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Anuncios win = new Anuncios();
            win.Show();
        }
        private void pnlNoticias_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Noticias win = new Noticias();
            win.Show();
        }
        private void pnlAgenda_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Agenda win = new Agenda();
            win.Show();
        }
        private void pnlAniversarios_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Aniversarios win = new Aniversarios();
            win.Show();
        }





    }
}
